package gyroscope;

import javax.media.opengl.*;
import javax.media.opengl.glu.GLU;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JPanel;


import com.sun.opengl.util.FPSAnimator;
import com.sun.opengl.util.GLUT;

import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
public class Gyroscope 
       implements  GLEventListener, MouseListener, MouseMotionListener, KeyListener
{	
	private GLCanvas canvas;		//OpenGL-Canvas
	private FPSAnimator anim;
	private GLUT glut = new GLUT();
	private boolean log = false;
	private double xmin = -0.6;
	private double xmax = 0.6;
	private double ymin	;
	private double ymax;
	//viewing volumen vergroessen, heist clipping bereich vergroessen
	double zmin = -100, zmax = 100; // Clipping Bereich

	
	double elev = 20; // Elevation Kamera-System
	double azim = 30; // Azimut Kamera-System	
	//Zeitschritt
	private double dt = 2;
	
	
	
	
	private double c_radius = 0.09;
	private double c_height = 0.025;
	
	private double t = -10;
	    
	//  ------------------  Methoden  --------------------	
		
	void zeichneRotor(GL gl){
		gl.glPushMatrix();
		gl.glColor3d(0.5, 0.5, 0.5);
		gl.glRotated(-90, 1, 0, 0);
		gl.glRotated(-t, 0, 0, 1);
		gl.glColor3d(0.54, 0.27, 0.07);
		glut.glutSolidCylinder(c_radius/16, -8*c_height, 15, 10);
		glut.glutSolidCylinder(c_radius/16, 4.5*c_height, 15, 10);
		gl.glColor3d(0.5, 0.5, 0.5);
		glut.glutSolidCylinder(c_radius, c_height, 15, 10);
		glut.glutWireCone(c_radius/4, 3*c_height, 15, 10);
		gl.glTranslated(0, 0, 0.01);
		gl.glColor3d(0.93, 0.93, 0);
		glut.glutSolidTorus(c_radius/16, c_radius+0.01, 2, 100);
		gl.glPopMatrix();
		gl.glRotated(-t, 0, 1,0);
		glut.glutSolidTorus(c_radius/16, c_radius+0.02, 2, 100);
		gl.glRotated(-90, 1, 0, 0);
		
		

		if (t==360)t = 0;
		t+=-dt;
	}
			

	 		
	// Koordinatenachsen zeichnen
	void zeichneAchsen(GL gl) {
		gl.glBegin(GL.GL_LINES);
		// x-Achse
		gl.glColor3d(1.0, 0.0, 0.0);
		gl.glVertex3d(xmin/2, 0,0);
		gl.glVertex3d(xmax/2, 0,0);
		// y-Achse
		gl.glColor3d(0.0, 0.0, 1.0);
		gl.glVertex3d(0, -ymax/2,0);
		gl.glVertex3d(0, ymax/2,0);
		// z-Achse
		gl.glColor3d(0.0, 1.0, 0.0);
		gl.glVertex3d(0, 0,0);
		gl.glVertex3d(0, 0,0.2);
						
		gl.glEnd();
		
	}



     // Konstruktor
     public Gyroscope()
     {  
    	Frame f = new Frame("Gyroscope");
        f.setSize(1280, 960);
//      f.addWindowListener(this);
        // OpenGL-Window
        canvas = new GLCanvas();
        canvas.addKeyListener(this);
        canvas.addGLEventListener(this);
        canvas.addMouseListener(this);
        f.add(canvas);
        f.setVisible(true);
        canvas.requestFocus();
     }
     
     
     public Gyroscope(GLJPanel jp){
         // OpenGL-Window
//         f.addWindowListener(this);
         jp.addKeyListener(this);
         jp.addGLEventListener(this);
         jp.addMouseListener(this);
         jp.setVisible(true);
         jp.requestFocus();
     }
     

     public static void main(String[] args)                     // main-Methode der Applikation
     {  new Gyroscope();
     }


     //  ---------  OpenGL-Events  -----------------------

	public void init(GLAutoDrawable drawable) {
		//OpenGL-Objekt
		GL gl = drawable.getGL();
		gl.glClearColor(0.68f, 0.84f, 0.9f, 1.0f); // erasing color
		
		//aktivieren des z Buffers
		gl.glEnable(GL.GL_DEPTH_TEST);
		//aktivieren des Polygon Offset
		gl.glEnable(GL.GL_POLYGON_OFFSET_FILL);
		//zu den Z-Werten wir ein Offset hinzugefuegt, so das die Z Werte nicht die gleichen Werte haben
		gl.glPolygonOffset(1,1);
		//Beleuchtung aktivieren
		gl.glEnable(GL.GL_LIGHTING);
		//Wichtig: so das alle Richtungen normalisiert werden
		gl.glEnable(GL.GL_NORMALIZE);
		//Lichtquellen einschalten, positionierung in display methode
		//Aktiviert die 0 Lichtquelle
		gl.glEnable(GL.GL_LIGHT0);
		//ShadeModel einfuegen, default ist es smooth, flat ist schneller
		//bei flat hat eine flaeche, genau eine helligkeit, bei smooth werden die lichtpunkte
		//innerhalb einer flaeche noch interpoliert.
		gl.glShadeModel(GL.GL_SMOOTH);
		//diffusen koeffizienten komponenten, 3 rgb und durchsichtigkeit
		float[] werte = {1f, 1f, 1f, 1.0f};
		//hinten relativ dunkel -> muss streulicht erhoehen
		gl.glMaterialfv(GL.GL_FRONT, GL.GL_DIFFUSE, werte,0);
		float[] noAmbient = { 0.2f, 0.2f, 0.2f, 1f }; 	// low ambient light
		float[] diffuse =  { 1f, 1f, 1f, 1f };		// full diffuse colour
		gl.glLightfv(GL.GL_LIGHT0, GL.GL_AMBIENT, noAmbient, 0);
		gl.glLightfv(GL.GL_LIGHT0, GL.GL_DIFFUSE, diffuse, 0);
		anim = new FPSAnimator(drawable, 60, true);
		anim.start();
	     
	}


	public void display(GLAutoDrawable drawable) {
		GL gl = drawable.getGL();
		gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
				
		gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL.GL_LINE);
		gl.glMatrixMode(GL.GL_MODELVIEW);
		gl.glLoadIdentity();
		// Kamera-System positionieren:
		// Kamera vom System weg bewegen, hat aber fuer die orthogonale
		// Projektion keine Wirkung, erst wenn die eleveation dazu kommt spielt
		// dies eine Rolle
		gl.glTranslated(0, 0, 0.1);
		// wichtig elevation nach dem translate;
		// notizen: ensrpicht der 1 Variante: absolute Variante
		gl.glRotated(elev, 1, 0, 0); // Drehung um x-Achse
		gl.glRotated(-azim, 0, 1, 0); // Drehung um y-Achse

		// Achsen sollen nicht beleuchtet sein
		gl.glColor3d(0, 0, 0.1);

		// Hier Position der Kamera, muss die Koordinaten in einem Float Array
		// vorbereiten
		float[] pos = { 1000, 1000, -1000, 1 };
		// Die Koordinaten des Lichts werden in das Kamerasystem umgerechnet
		// bewege ich nur die Kamera, dann haben wir eine andere Beleuchtung
		gl.glLightfv(gl.GL_LIGHT0, GL.GL_POSITION, pos, 0);
		gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL.GL_FILL);
		
		//Objektsystem drehen da in OpenGL die Koordinatenachsen anders sind
		//Drehung um die X-Achse
//		gl.glRotated(-90,1,0,0);
		//Drehumg um die z Achse
//		gl.glRotated(-90,0,0,1);	
		gl.glDisable(GL.GL_LIGHTING);
		zeichneAchsen(gl);
//		gl.glEnable(GL.GL_LIGHTING);
		gl.glTranslated(0, 0, 0);
		gl.glRotated(-t/4, 0, 1, 0);
		gl.glRotated(-45, 0, 0, 1);
		gl.glTranslated(0.0, 0.20, 0);
		zeichneRotor(gl);
	}

	//Window resized
     public void reshape(GLAutoDrawable drawable,
                         int x, int y,
                         int width, int height)
     {  
//    	 System.out.println("Reshaping...");
    	 GL gl = drawable.getGL();
     //damit keine Verzerrungen enstehen
     	ymax = xmax * height / width;
     	ymin = -ymax;
     	gl.glMatrixMode(GL.GL_PROJECTION);
     	gl.glLoadIdentity();
        gl.glOrtho(xmin, xmax, ymin, ymax, zmin, zmax);
        gl.glViewport(0, 0, width, height);
     }

     public void displayChanged(GLAutoDrawable drawable,
                                boolean modeChanged,
                                boolean deviceChanged)
     { }


     //  ---------  Window-Events  --------------------

     public void windowClosing(WindowEvent e)
     {  System.exit(0);
     }
     public void windowActivated(WindowEvent e) {  }
     public void windowClosed(WindowEvent e) {  }
     public void windowDeactivated(WindowEvent e) {  }
     public void windowDeiconified(WindowEvent e) {  }
     public void windowIconified(WindowEvent e) {  }
     public void windowOpened(WindowEvent e) {  }

 	//  ---------  Mouse Events  --------------------

 	@Override
 	public void mouseDragged(MouseEvent e) {

 	}


 	@Override
 	public void mouseMoved(MouseEvent e) {

 	}
 	
 	@Override
	public void mouseClicked(MouseEvent e) {
		// TODO Auto-generated method stub

	}

	@Override
	public void mouseEntered(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void mouseExited(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void mousePressed(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void mouseReleased(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}
	
//  ---------  Key Events  --------------------

	@Override
	public void keyPressed(KeyEvent e) {
		switch (e.getKeyCode()) {
		case KeyEvent.VK_S:
				if (anim.isAnimating()) {
					anim.stop();
				} else {
					anim.start();
				}
			break;
		case KeyEvent.VK_UP:
			elev++;
			canvas.repaint();
			break;
		case KeyEvent.VK_DOWN:
			elev--;
			canvas.repaint();
			break;
		case KeyEvent.VK_LEFT:
			azim++;
			canvas.repaint();
			break;
		case KeyEvent.VK_RIGHT:
			azim--;
			canvas.repaint();
			break;
		case KeyEvent.VK_R:
			break;
		case KeyEvent.VK_N:
			break;
		case KeyEvent.VK_M:
			break;
		default:
			break;
		}
	}

	@Override
	public void keyReleased(KeyEvent e) {}

	@Override
	public void keyTyped(KeyEvent e) {}
	
	private void log(String msg){
		if (log)
			System.out.println(msg);
	}
  }